package v1

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"time"
	"web_framework/config"
	"web_framework/model"
	"web_framework/pkg/constvar"
	. "web_framework/pkg/e"
	"web_framework/pkg/errno"
	"web_framework/router/api"
	"web_framework/router/middleware"
	"web_framework/service"
	"web_framework/storage"

	"web_framework/pkg/e"
)

type UserAPI struct {
	Uid         int    `db:"uid" json:"uid"`
	NickName    string `db:"nickname" json:"nickname,omitempty"`
	PhoneArea   string `db:"phone_area" json:"phone_area,omitempty"`
	PhoneNumber string `db:"phone_number" json:"phone_number,omitempty"`
	Password    string `db:"password" json:"password"`
}

func (a UserAPI) Name() string {
	return "user API"
}

func (a UserAPI) Bind() {
	userAPI := config.C.Router.Group("/api/v1/data", middleware.CheckVer(), middleware.TrackLog())
	{
		userAPI.POST("test", Test)
		userAPI.GET("testSms", TestSmsCode)
		userAPI.GET("testEmailQQ", TestEmailQQ)

		userAPI.GET("user/init", Init)
		userAPI.GET("user/login", Login)
		userAPI.GET("user/register", Register)
		userAPI.GET("user/send_sms_code", SendSmsCode)
		userAPI.GET("user/mobile_login", MobileLogin)
		userAPI.GET("user/check_register_code", CheckRegisterCode)
		userAPI.GET("user/mobile_password", MobilePassword)
		userAPI.GET("user/email_sms", EmailSms)
		userAPI.GET("user/email_code", EmailCode)
		userAPI.GET("user/email_password", EmailPassword)
		userAPI.GET("user/info", UserInfo)
		userAPI.GET("user/logout", UserLogout)
		userAPI.GET("user/update_password", UpdatePassword)
		userAPI.GET("user/unbind_router", UnbindRouter)
		userAPI.GET("user/join_device_info", JoinDeviceInfo)
	}
}

// 1.6 APP 登录 初始化 
func Init(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"uid", "sver"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	token := c.Query("token")
	if token == "" {
		api.SendResponse(c, errno.TokenError, nil)
		return
	}

	uid, _ := strconv.Atoi(params["uid"])
	err, bo := service.CheckUserToken(uid, token)
	if !bo || err != nil {
		api.SendResponse(c, errno.TokenError, nil)
		return
	}

	errno.OK.Info = "Token 正常"
	api.SendResponse(c, errno.OK, nil)
}

// 5.1节 账号密码登录接口
func Login(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"nickname", "password", "t", "sign"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验签名
	nickname := params["nickname"]
	password := params["password"]
	sign := params["sign"]
	t := params["t"]
	if t == "" || sign == "" {
		errno.ParamsEmpty.Info += "parameter error" + " :sign,t"
		api.SendResponse(c, errno.ParamsEmpty, nil)
		return
	}
	paramsSign := []string{t, nickname, password}
	err = CheckSign(sign, paramsSign)
	if err != nil {
		api.SendResponse(c, errno.SignError, nil)
		return
	}

	// 密码校验流程
	errorCount := 0
	var user model.User
	dbQuery := config.C.DB.DB

	// 1、校验是否在黑名单列表
	ip := GetPublicIP()
	ipKey := constvar.RedisUserBanIP + ip
	if storage.RedisExists(ipKey) {
		api.SendResponse(c, errno.BanError, nil)
		return
	}

	// 2、校验是否存在账号  优先级 校验 邮箱 > 用户名 > 手机号
	if IsEmail(nickname) {
		Log("Info", " nickname[", nickname, "] is email address ")
		user, err = storage.GetUserByEmail(dbQuery, nickname)
		if err != nil {
			api.SendResponse(c, errno.ErrDatabase, nil)
			return
		}
	} else {
		user, err = storage.GetUserByName(dbQuery, nickname)
		if err == nil {
			if CheckPassword(password, user.Password, user.Salt) == false {
				errorCount += 1
				Log("Info", " nickname[", nickname, "] maybe a nickname , password is wrong. ")
				Log("Info", errorCount)
			}
		} else {
			// 仅支持中国地区手机号直接登录
			if IsPhone(nickname) {
				user, err = storage.GetUserByPhone(dbQuery, 86, nickname)
			}
		}
	}
	if errorCount <= 0 && CheckPassword(password, user.Password, user.Salt) == false {
		errorCount += 1
		Log("Info", strconv.Itoa(user.Uid), " password is wrong1")
		Log("Info", errorCount)
	}


	Log("Info", "errorCount = ", errorCount)
	// 3、校验是否 一个小时内 超过输入8次错误密码  采用新的redis来做处理
	if errorCount > 0 {
		errorCountKey := constvar.RedisUserLoginErr + ip
		if storage.RedisExists(errorCountKey) {
			errNumN, _ := storage.RedisIncr(errorCountKey)
			if errNumN >= constvar.BanIpLimit {
				// 超过10次加入黑名单1个小时
				storage.RedisSet(ipKey, ip, constvar.RedisExpireHour)
				api.SendResponse(c, errno.BanError, nil)
				return
			}
		} else {
			storage.RedisSet(errorCountKey, 1, constvar.RedisExpireHour)
		}

		api.SendResponse(c, errno.ErrPasswordIncorrect, nil)
		return
	}

	// 4、校验是否 账号密码正确  正确：写入token表、写入redis
	client, _ := strconv.Atoi(c.Query("client"))
	err, token := service.AddUserToken(user.Uid, client, "") // 暂时不考虑极光推送ID
	if err != nil {
		api.SendResponse(c, errno.ErrTokenError, nil)
	} else {
		var dataReturn model.LoginRequest
		dataReturn.Uid = user.Uid
		dataReturn.Token = token
		//TODO 需要把用户详情数据写入到redis  userInfoKey := constvar.RedisUserInfo + params["uid"]

		errno.OK.Info = "用户登录成功"
		api.SendResponse(c, errno.OK, dataReturn)
	}
}

// 手机号登录发送短信验证码
func SendSmsCode(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"area", "mobile", "t", "sign", "scene"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验签名
	t := params["t"]
	area := params["area"]
	mobile := params["mobile"]
	sign := params["sign"]
	if t == "" || sign == "" {
		errno.ParamsEmpty.Info += "parameter error" + " :sign,t"
		api.SendResponse(c, errno.ParamsEmpty, nil)
		return
	}
	paramsSign := []string{t, area, mobile}
	err = CheckSign(sign, paramsSign)
	if err != nil {
		api.SendResponse(c, errno.SignError, nil)
		return
	}

	// 发送短信
	var dataReturn model.SmsCodeRequest
	// 1、校验是否在黑名单列表
	ip := GetPublicIP()
	ipKey := constvar.RedisUserBanIP + ip
	if storage.RedisExists(ipKey) {
		api.SendResponse(c, errno.BanError, nil)
		return
	}

	// 2、校验IP是否被限制了次数
	ipSmsKey := constvar.RedisSmsBanIP + ip
	if storage.RedisExists(ipSmsKey) {
		sendCountStr, _ := storage.RedisGet(ipSmsKey)
		sendCount, _ := strconv.Atoi(sendCountStr)
		if sendCount > constvar.SmsCodeLimit {
			api.SendResponse(c, errno.SmsLimitError, nil)
			return
		}
	}

	// 3、校验是否已经发送成功
	isSendSmsKey := constvar.RedisSmsSend + ip + area + mobile
	if storage.RedisExists(isSendSmsKey) {
		if config.C.RunMode == "debug" {
			code, _ := storage.RedisGet(isSendSmsKey)
			dataReturn.Code, _ = strconv.Atoi(code)
			errno.OK.Info = "发送短信成功"
			api.SendResponse(c, errno.OK, dataReturn)
			return
		}
		api.SendResponse(c, errno.ErrSendSmsError, nil)
		return
	}

	// 注意：
	// 此处需新增字段 scene = 1 login / 2 register / 3 password
	// 如果  scene = 1 login / 3 password 需要判断 是否已经存在记录  不存在则报错
	// 如果  scene = 2 register			  需要判断 是否已经存在记录  存在则报错
	// 4、是否该用户已经注册过
	areaNum, _ := strconv.Atoi(area)
	_, err = storage.GetUserByPhone(config.C.DB.DB, areaNum, mobile)
	sceneNum, _ := strconv.Atoi(params["scene"])
	if err != nil {
		if sceneNum == 1 || sceneNum == 3 {
			api.SendResponse(c, errno.ErrUnLogin, nil)
			return
		}
	} else {
		if sceneNum == 2 {
			api.SendResponse(c, errno.ErrRegistered, nil)
			return
		}
	}

	// 5、发送短信
	code, err := SendSMS(mobile, areaNum)
	if err == nil {
		// 设置发送成功的短信到redis做校验
		storage.RedisSet(isSendSmsKey, code, constvar.RedisExpireMinute5)
		// 设置已经发送短信的次数
		if storage.RedisExists(ipSmsKey) {
			storage.RedisIncr(ipSmsKey)
		} else {
			storage.RedisSet(ipSmsKey, 1, constvar.RedisExpireDay)
		}

		dataReturn.Code = code
		errno.OK.Info = "发送短信成功"
		api.SendResponse(c, errno.OK, dataReturn)
	} else {
		api.SendResponse(c, err, nil)
	}
}

// 手机号验证码登录
func MobileLogin(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"area", "mobile", "code"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验输入的验证码和短信验证是否一致
	ip := GetPublicIP()
	area := params["area"]
	mobile := params["mobile"]
	sendSmsKey := constvar.RedisSmsSend + ip + area + mobile
	if storage.RedisExists(sendSmsKey) {
		smsCode, err := storage.RedisGet(sendSmsKey)
		if err != nil {
			api.SendResponse(c, errno.SmsError, nil)
			return
		}
		if smsCode != params["code"] {
			api.SendResponse(c, errno.ErrSmsValid, nil)
			return
		}
	} else {
		// 短信过期 重新获取
		api.SendResponse(c, errno.ErrSmsExpire, nil)
		return
	}

	// 登录校验
	areaNum, _ := strconv.Atoi(area)
	user, err := storage.GetUserByPhone(config.C.DB.DB, areaNum, mobile)
	if err != nil {
		api.SendResponse(c, errno.ErrDatabase, nil)
		return
	}

	// 生成token
	client, _ := strconv.Atoi(c.Query("client"))
	err, token := service.AddUserToken(user.Uid, client, "") // 暂时不考虑极光推送ID
	if err != nil {
		api.SendResponse(c, errno.ErrTokenError, nil)
		return
	}

	var dataReturn model.LoginRequest
	dataReturn.Uid = user.Uid
	dataReturn.Token = token
	errno.OK.Info = "登录成功"
	api.SendResponse(c, errno.OK, dataReturn)
}

// 手机号注册 短信验证码 验证
func CheckRegisterCode(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"area", "mobile", "code"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验短信
	// 1、校验是否在黑名单列表
	ip := GetPublicIP()
	ipKey := constvar.RedisUserBanIP + ip
	if storage.RedisExists(ipKey) {
		api.SendResponse(c, errno.BanError, nil)
		return
	}

	// 2、校验IP是否被限制了次数
	ipSmsKey := constvar.RedisSmsBanIP + ip
	if storage.RedisExists(ipSmsKey) {
		sendCountStr, _ := storage.RedisGet(ipSmsKey)
		sendCount, _ := strconv.Atoi(sendCountStr)
		if sendCount > constvar.SmsCodeLimit {
			api.SendResponse(c, errno.SmsLimitError, nil)
			return
		}
	}

	// 3、校验是否已经发送成功
	area := params["area"]
	mobile := params["mobile"]
	sendSmsKey := constvar.RedisSmsSend + ip + area + mobile
	if storage.RedisExists(sendSmsKey) {
		smsCode, err := storage.RedisGet(sendSmsKey)
		if err != nil {
			api.SendResponse(c, errno.SmsError, nil)
			return
		}
		if smsCode != params["code"] {
			api.SendResponse(c, errno.ErrSmsValid, nil)
			return
		}
	} else {
		// 短信过期 重新获取
		api.SendResponse(c, errno.ErrSmsExpire, nil)
		return
	}

	// TODO 可以切换为List 数据类型
	var UniqueCode model.UniqueCodeRequest
	UniqueCode.UniqueCode = GetUuid()
	UniqueAreaKey := constvar.RedisUniqueCode + UniqueCode.UniqueCode + ":area"
	UniqueMobileKey := constvar.RedisUniqueCode + UniqueCode.UniqueCode + ":mobile"
	storage.RedisSet(UniqueAreaKey, area, constvar.RedisExpireMinute5)
	storage.RedisSet(UniqueMobileKey, mobile, constvar.RedisExpireMinute5)
	errno.OK.Info = "短信验证成功"
	Log("Info", "短信校验成功：缓存数据 UniqueCode:[", UniqueCode.UniqueCode, "]")
	api.SendResponse(c, errno.OK, UniqueCode)
}

// 5.3.3 注册接口
func Register(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"unique_code", "password"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验 唯一码是否匹配
	UniqueCode := params["unique_code"]
	UniqueAreaKey := constvar.RedisUniqueCode + UniqueCode + ":area"
	UniqueMobileKey := constvar.RedisUniqueCode + UniqueCode + ":mobile"
	if storage.RedisExists(UniqueAreaKey) && storage.RedisExists(UniqueMobileKey) {
		UnlockPassword := c.Query("password")
		// 校验密码的合法性
		if ! YYetsPasswordCheck(UnlockPassword) {
			api.SendResponse(c, errno.ErrPassword, nil)
			return
		}
		salt := GetRandomStr(6)
		area, _ := storage.RedisGet(UniqueAreaKey)
		mobile, _ := storage.RedisGet(UniqueMobileKey)
		nickname := c.Query("nickname")
		password := CreatePassword(UnlockPassword, salt)
		// 判断是否有注册过
		areaNum, _ := strconv.Atoi(area)
		userInfo, err := storage.GetUserByPhone(config.C.DB.DB, areaNum, mobile)
		if err == nil && userInfo.Uid > 0 {
			api.SendResponse(c, errno.ErrRegistered, nil)
			return
		}

		// 完成注册
		var createUser model.RegisterUser
		createUser.Salt = salt
		createUser.PhoneNumber = mobile
		createUser.PhoneArea = area
		if nickname == "" {
			createUser.Nickname = mobile
		} else {
			createUser.Nickname = nickname
		}

		// 判断用户输入的用户名是否已经注册过
		existsUser, err := storage.GetUserByName(config.C.DB.DB, createUser.Nickname)
		if existsUser.Uid > 0 {
			api.SendResponse(c, errno.ErrNickNameUsed, nil)
			return
		}

		createUser.PinYin = "" // TODO 中文转英文
		createUser.Password = password
		createUser.CreateIp = IpToInt(GetPublicIP())
		uid, err := storage.RegisterCreateUser(config.C.DB.DB, &createUser)
		if err != nil {
			api.SendResponse(c, errno.ErrDatabase, nil)
			return
		}

		// 生成用户token
		client, _ := strconv.Atoi(c.Query("client"))
		err, token := service.AddUserToken(uid, client, "") // 暂时不考虑极光推送ID
		if err != nil {
			api.SendResponse(c, errno.ErrTokenError, nil)
			return
		}
		returnData := model.LoginRequest{
			Uid:   uid,
			Token: token,
		}

		// 完成注册之后需要做 初始化操作
		ip := GetPublicIP()
		ipInt := IpToInt(ip)
		service.UserRegisterInit(uid, ipInt)

		errno.OK.Info = "注册成功"
		api.SendResponse(c, errno.OK, returnData)
		return
	}

	api.SendResponse(c, errno.ErrValidRegister, nil)
}

// 5.4.3 修改密码接口
func MobilePassword(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"unique_code", "password"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验 唯一码是否匹配
	UniqueCode := params["unique_code"]
	UniqueAreaKey := constvar.RedisUniqueCode + UniqueCode + ":area"
	UniqueMobileKey := constvar.RedisUniqueCode + UniqueCode + ":mobile"

	// 调试模式采用
	if storage.RedisExists(UniqueAreaKey) && storage.RedisExists(UniqueMobileKey) {
		// 判断是否有注册过
		area, _ := storage.RedisGet(UniqueAreaKey)
		mobile, _ := storage.RedisGet(UniqueMobileKey)
		areaNum, _ := strconv.Atoi(area)
		userInfo, err := storage.GetUserByPhone(config.C.DB.DB, areaNum, mobile)
		var salt, password string
		isNeedUpdate := 1 //默认需要修改
		if err == nil && userInfo.Uid > 0 {
			salt = userInfo.Salt
			if CheckPassword(params["password"], userInfo.Password, salt) {
				isNeedUpdate = 0
			}else {
				password = CreatePassword(params["password"], salt)
			}
		} else {
			api.SendResponse(c, errno.ErrUnLogin, nil)
			return
		}

		// 完成修改密码
		Uid := userInfo.Uid
		if isNeedUpdate == 1 {
			var updateUser model.UpdatarUser
			updateUser.Uid = Uid
			updateUser.Password = password
			updateUser.UpdateTime = time.Now().Unix()
			err = storage.UpdateUserPassword(config.C.DB.DB, &updateUser)
			if err != nil {
				api.SendResponse(c, errno.ErrDatabase, nil)
				return
			}
		}

		// 生成用户token
		client, _ := strconv.Atoi(c.Query("client"))
		err, token := service.AddUserToken(Uid, client, "") // 暂时不考虑极光推送ID
		if err != nil {
			api.SendResponse(c, errno.ErrTokenError, nil)
			return
		}

		returnData := model.LoginRequest{
			Uid:   Uid,
			Token: token,
		}
		errno.OK.Info = "找回密码成功"
		api.SendResponse(c, errno.OK, returnData)
		return
	}

	Log("Info", "缓存找不到数据 UniqueCode:[", UniqueCode, "]")

	api.SendResponse(c, errno.ErrValidFindPassword, nil)
	return
}

// 5.5.1 发送邮件验证码接口
func EmailSms(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"email", "t", "sign"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验签名
	t := params["t"]
	email := params["email"]
	sign := params["sign"]
	if t == "" || sign == "" {
		api.SendResponse(c, errno.SignError, nil)
		return
	}
	paramsSign := []string{t, email}
	err = CheckSign(sign, paramsSign)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验IP是否被限制了次数
	ip := GetPublicIP()
	ipSmsKey := constvar.RedisSmsBanIP + ip
	if storage.RedisExists(ipSmsKey) {
		sendCountStr, _ := storage.RedisGet(ipSmsKey)
		sendCount, _ := strconv.Atoi(sendCountStr)
		if sendCount > constvar.SmsCodeLimit {
			api.SendResponse(c, errno.SmsLimitError, nil)
			return
		}
	}

	// 校验是否已经发送过邮件
	emailKey := constvar.RedisEmailSend + ip + ":" + email
	if storage.RedisExists(emailKey) {
		api.SendResponse(c, errno.ErrSendSmsError, nil)
		return
	}

	// 校验该邮箱是否已经注册过账号
	user ,err := storage.GetUserByEmail(config.C.DB.DB, email)
	if err != nil || user.Uid <= 0 {
		api.SendResponse(c, errno.ErrEmailUnLogin, nil)
		return
	}

	// 发送邮件验证码
	code := GetRandomStr(6)
	err = EmailFindPassWord(email, code)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	storage.RedisSet(emailKey, code, constvar.RedisExpireMinute5)
	errno.OK.Info = "密码找回成功"
	api.SendResponse(c, errno.OK, &model.DataResponse{Code: code})
}

// 5.5.2 邮件验证码校验
func EmailCode(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"email", "code"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	// 校验是否在黑名单列表
	ip := GetPublicIP()
	ipKey := constvar.RedisUserBanIP + ip
	if storage.RedisExists(ipKey) {
		api.SendResponse(c, errno.BanError, nil)
		return
	}

	// 校验IP是否被限制了次数
	ipSmsKey := constvar.RedisSmsBanIP + ip
	if storage.RedisExists(ipSmsKey) {
		sendCountStr, _ := storage.RedisGet(ipSmsKey)
		sendCount, _ := strconv.Atoi(sendCountStr)
		if sendCount > constvar.SmsCodeLimit {
			api.SendResponse(c, errno.SmsLimitError, nil)
			return
		}
	}

	// 校验是否已经发送成功
	email := params["email"]
	emailKey := constvar.RedisEmailSend + ip+ ":" + email
	if storage.RedisExists(emailKey) {
		code, err := storage.RedisGet(emailKey)
		if err != nil {
			api.SendResponse(c, errno.EmailError, nil)
			return
		}
		if code != params["code"] {
			api.SendResponse(c, errno.ErrEmailValid, nil)
			return
		}
	} else {
		// 短信过期 重新获取
		api.SendResponse(c, errno.ErrEmailExpire, nil)
		return
	}

	// 生成唯一码
	UniqueCode := GetUuid()
	UniqueMobileKey := constvar.RedisUniqueCode + UniqueCode + ":email"
	storage.RedisSet(UniqueMobileKey, email, constvar.TimeFormatMin * 5)
	Log("War", "UniqueMobileKey: ", UniqueMobileKey)
	errno.OK.Info = "短信验证成功"
	api.SendResponse(c, errno.OK, &model.DataResponse{UniqueCode: UniqueCode})
}

// 5.5.3 修改密码接口
func EmailPassword(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"unique_code", "password"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, params)
		return
	}

	// 校验 唯一码是否匹配
	UniqueCode := params["unique_code"]
	UniqueMobileKey := constvar.RedisUniqueCode + UniqueCode + ":email"
	Log("War", "UniqueMobileKey: ", UniqueMobileKey)

	if storage.RedisExists(UniqueMobileKey) {
		// 判断是否有注册过
		email, err := storage.RedisGet(UniqueMobileKey)
		userInfo, err := storage.GetUserByEmail(config.C.DB.DB, email)
		var salt, password string
		isNeedUpdate := 1 //默认需要修改
		if err == nil && userInfo.Uid > 0 {
			salt = userInfo.Salt
			if CheckPassword(params["password"], userInfo.Password, salt) {
				isNeedUpdate = 0
			}
			password = CreatePassword(params["password"], salt)
		} else {
			api.SendResponse(c, errno.ErrUnLogin, nil)
			return
		}

		// 完成修改密码
		Uid := userInfo.Uid
		if isNeedUpdate == 1 {
			var updateUser model.UpdatarUser
			updateUser.Uid = Uid
			updateUser.Password = password
			updateUser.UpdateTime = time.Now().Unix()
			err = storage.UpdateUserPassword(config.C.DB.DB, &updateUser)
			if err != nil {
				api.SendResponse(c, errno.ErrDatabase, nil)
				return
			}
		}

		// 生成用户token
		client, _ := strconv.Atoi(c.Query("client"))
		err, token := service.AddUserToken(Uid, client, "") // 暂时不考虑极光推送ID
		if err != nil {
			api.SendResponse(c, errno.ErrTokenError, nil)
			return
		}

		returnData := model.LoginRequest{
			Uid:   Uid,
			Token: token,
		}
		errno.OK.Info = "找回密码成功"
		api.SendResponse(c, errno.OK, returnData)
		return
	}

	api.SendResponse(c, errno.ErrValidFindPassword, nil)
}

// 5.8 用户信息及详情
func UserInfo(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"uid", "token", "sn"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, params)
		return
	}

	uid, _ := strconv.Atoi(params["uid"])
	sn := params["sn"]
	userInfo, err := service.GetUserInfo(uid, sn, 1)
	if err != nil {
		api.SendResponse(c, errno.ErrDatabase, nil)
		return
	}

	api.SendResponse(c, errno.OK, userInfo)
}

// 5.9 退出登录
func UserLogout(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"uid", "token"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, params)
		return
	}

	uid, _ := strconv.Atoi(params["uid"])
	token := params["token"]

	// 删除redis缓存
	userInfoKey := constvar.RedisUserInfo + params["uid"]
	if storage.RedisExists(userInfoKey) {
		storage.RedisExpire(userInfoKey, -1)
	}
	err = storage.DeleteUserTokenByUidToken(config.C.DB.DB, uid, token)
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	errno.OK.Info = "退出登录成功"
	api.SendResponse(c, errno.OK, nil)
}

// 5.10 端内修改密码
func UpdatePassword(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"uid", "token", "old_password", "new_password"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, params)
		return
	}

	// 去校验uid 和 token 是否合法
	uid, _ := strconv.Atoi(params["uid"])
	userInfo, err := storage.GetUserByUid(config.C.DB.DB, uid)
	if err != nil || userInfo.Uid < 1 {
		api.SendResponse(c, errno.ErrUserNotFound, nil)
		return
	}

	// 校验密码是否合法
	if !YYetsPasswordCheck(params["new_password"]) {
		api.SendResponse(c, errno.ErrPassword, nil)
		return
	}

	// 校验密码是否匹配
	if !CheckPassword(params["old_password"], userInfo.Password, userInfo.Salt) {
		api.SendResponse(c, errno.ErrPasswordIncorrect, nil)
		return
	}

	// 修改密码
	var updateUser model.UpdatarUser
	updateUser.Uid = uid
	updateUser.Password = CreatePassword(params["new_password"], userInfo.Salt)
	updateUser.UpdateTime = time.Now().Unix()
	err = storage.UpdateUserPassword(config.C.DB.DB, &updateUser)
	if err != nil {
		api.SendResponse(c, errno.ErrDatabase, nil)
		return
	}
	errno.OK.Info = "修改密码成功"
	api.SendResponse(c, errno.OK, nil)
}

// 5.11 解绑路由器
func UnbindRouter(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"uid", "token", "sn"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, params)
		return
	}

	uid, _ := strconv.Atoi(params["uid"])
	// 校验是否已经绑定过该设备，没有绑定则返回错误信息
	err = service.DeviceUnbind(uid, params["sn"])
	if err != nil {
		api.SendResponse(c, err, nil)
		return
	}

	errno.OK.Info = "解绑路由器成功"
	api.SendResponse(c, errno.OK, nil)
}

// 5.12 连接设备信息
func JoinDeviceInfo(c *gin.Context) {

	// 检查参数是否为空
	checkList := []string{"uid", "token", "sn"}
	err, params := CheckEmptyParams(c, checkList)
	if err != nil {
		api.SendResponse(c, err, params)
		return
	}

	errno.OK.Info = "返回连接设备列表信息"
	api.SendResponse(c, errno.OK, nil)
}

func TestEmailQQ(c *gin.Context) {

	errno.OK.Info = "邮件发送成功"
	api.SendResponse(c, errno.OK, nil)
}

// 测试网络请求
func Test(c *gin.Context) {

	//code := 1002
	//msg := "TODO"
	////dataS := "xx"
	//
	//a,_ := storage.RedisZRange("router:user:token:6281359",0, 0)
	//fmt.Println("---------------------")
	//fmt.Println(a)
	//fmt.Println("---------------------")
	//
	//var dataS string
	//for user := range a {
	//	dataS = a[user]
	//	fmt.Printf("Zrange name: %v %v\n", user, a[user])
	//}

	//redisKey := constvar.REDIS_USER_BAN_IP + strconv.Itoa(code)

	//vaule, err := redis.SMembers(redisKey)
	//if err {
	//	log.Info("redis key is exists")

	//data, er := redis.Get(redisKey)
	//if er != nil {
	//	code = 999
	//	msg = "get redis error,"+er.Error()
	//	log.Info(msg)
	//}
	//if len(data) <= 0 {
	//	msg = "get redis empty"
	//	code = 998
	//}else {
	//	errShal := json.Unmarshal(data, &dataS)
	//	if errShal != nil {
	//		code = 997
	//		msg = "redis data Unmarshal error,"+er.Error()
	//		log.Info(err)
	//	}
	//}
	//	log.Info(vaule)
	//}else {
	//	dataS = "234"
	//	a, b := redis.ZAdd(redisKey, dataS, time.Now().Unix())
	//	if b != nil {
	//		log.Info("redis set error. Info : ", a," ", b.Error())
	//	}else {
	//		log.Info("redis key is not exists")
	//	}
	//
	//}

	//userInfo, err := storage.GetUserInfoRelation(config.C.DB.DB, 6281359)
	//if err != nil {
	//	api.SendResponse(c, err, nil)
	//	return
	//}

	size := c.Query("size")
	s ,_ := strconv.ParseFloat(size, 64)
	pw := e.SpeedUnitConversion(s)
	//pw := CreatePassword("123456", "S9K985")
	//userInfo.TotalShareSize = SizeFormat(userInfo.TotalSize)
	api.SendResponse(c, errno.OK, pw)
}

func TestSmsCode(c *gin.Context) {

	msg := ""
	dataS := "send error ."
	//dataS, err := SendSMS("18827097756", 86)
	//if err {
	//	dataS = "send success."
	//}
	dataS = GetRandomStr(6)

	c.JSON(http.StatusOK, gin.H{
		"code": 1,
		"msg":  msg,
		"data": dataS,
	})
}